/**
 * 
 */
package jmine.tec.report.impl;

import java.util.Calendar;
import java.util.Date;
import java.util.Map;

import jmine.tec.report.metadata.ColumnMetaData;
import jmine.tec.report.metadata.ParameterDefinition;
import jmine.tec.report.metadata.ParameterType;

/**
 * @author takeshi
 * @version 22/08/2007
 */
public abstract class AbstractDatedDataColumn extends AbstractExecutableDataColumn {

    public static final String DATE_PARAM_KEY = "ExecutableDataColumn#params#date";

    public static final String DATE_PARAM_LABEL = "maps.report.column.parameter.date";

    /**
     * C'tor
     * 
     * @param key the column key
     * @param name the column name
     * @param params the parameter definition
     */
    public AbstractDatedDataColumn(final String key, final String name, final ParameterDefinition... params) {
        super(key, name, createDatedColumnMetaData(key, name, params));
    }

    /**
     * Creates a {@link ColumnMetaData} with a date parameter and other {@link ParameterDefinition}s
     * 
     * @param key the column key
     * @param name the column name
     * @param params overriding parameters
     * @return {@link ColumnMetaData}
     */
    public static ColumnMetaData createDatedColumnMetaData(final String key, final String name,
            final ParameterDefinition... params) {
        return createMetaData(key, name, createDateParameter(), params);
    }

    /**
     * Creates a default date parameter
     * 
     * @return {@link ParameterDefinition}
     */
    private static ParameterDefinition createDateParameter() {
        return new ParameterDefinition(DATE_PARAM_KEY, DATE_PARAM_LABEL, null, ParameterType.DATE);
    }

    /**
     * C'tor
     * 
     * @param key the column key
     * @param name the column name
     * @param metaData the base metadata
     * @param otherParams other parameters to append to this column metadata
     */
    public AbstractDatedDataColumn(final String key, final String name, final ColumnMetaData metaData,
            final ParameterDefinition... otherParams) {
        super(key, name, getBaseMetaData(key, name, metaData, createDateParameter(), otherParams));
    }

    /**
     * Finds the date parameter in the given {@link Map}, returning the default parameter value if it cannot be found.
     * 
     * @param paramMap o mapa de parametros
     * @return {@link Date} or <code>null</code>
     */
    protected final Date findDate(final Map<String, Object> paramMap) {
        return this.findDate(paramMap, (Date) this.getDefaultParameterValue(DATE_PARAM_KEY));
    }

    /**
     * Finds the date in the param map, returning the second parameter if it cannot be found in the map. If the object in the map is a
     * {@link Calendar}
     * 
     * @param paramMap the map of parameters
     * @param defaultDate the default date in case the date cannot be found on the map
     * @return {@link Date}
     */
    protected final Date findDate(final Map<String, Object> paramMap, final Date defaultDate) {
        Object obj = paramMap.get(DATE_PARAM_KEY);
        if (obj != null) {
            if (obj instanceof Date) {
                return (Date) obj;
            } else if (obj instanceof Calendar) {
                return ((Calendar) obj).getTime();
            } else {
                final Date parsed = this.parseDateFromObject(obj);
                if (parsed != null) {
                    return parsed;
                }
            }
        }
        return defaultDate;
    }

    /**
     * Parses the date from an arbitrary object. The default implementation simply return <code>null</code>, indicating that the given
     * object cannot be parsed.
     * <p>
     * Subclasses are allowed to override this method for custom behaviour
     * 
     * @param obj Object the object to parse
     * @return {@link Date} or <code>null</code> if the object cannot be parsed
     */
    protected Date parseDateFromObject(final Object obj) {
        return null;
    }

    /**
     * Tries to find the date on the map, returning the current time if it cannot be found.
     * 
     * @param paramMap the map of parameters
     * @return {@link Date}
     */
    protected final Date findDateOrNow(final Map<String, Object> paramMap) {
        return this.findDate(paramMap, new Date());
    }

}
